﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace Xceed.Silverlight.DataGrid
{
  #region Metadata

  [TemplatePart( Name = "SearchTextBox", Type = typeof( TextBox ) )]

  #endregion

  public class GroupNavigationSearchBox : ContentControlBase
  {
    #region Static Fields

    internal static readonly XceedRoutedEvent OnSearchGroupEvent = new XceedRoutedEvent();

    private static readonly Binding InternalDataContextBinding = new Binding();

    #endregion

    #region Constructor

    public GroupNavigationSearchBox()
    {
      this.DefaultStyleKey = typeof( GroupNavigationSearchBox );

      // Bind the DataContext to an internal property to be notify when
      // it changes. This way, we can clear the Value property when
      // the GroupNavControl is in a recycled GroupContainer.
      BindingOperations.SetBinding( this, GroupNavigationSearchBox.InternalDataContextProperty, GroupNavigationSearchBox.InternalDataContextBinding );
    }

    #endregion

    #region InternalDataContext Property

    internal static readonly DependencyProperty InternalDataContextProperty = DependencyProperty.Register(
      "InternalDataContext",
      typeof( object ),
      typeof( GroupNavigationSearchBox ),
      new PropertyMetadata(
        null,
        new PropertyChangedCallback( GroupNavigationSearchBox.OnInternalDataContextChanged ) ) );

    private static void OnInternalDataContextChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      GroupNavigationSearchBox groupNavigationSearchBox = sender as GroupNavigationSearchBox;

      if( groupNavigationSearchBox == null )
        return;

      groupNavigationSearchBox.ClearValue( GroupNavigationSearchBox.ValueProperty );
    }

    #endregion

    #region WatermarkContent Property

    public static readonly DependencyProperty WatermarkContentProperty = DependencyProperty.Register(
      "WatermarkContent",
      typeof( object ),
      typeof( GroupNavigationSearchBox ),
      new PropertyMetadata( ( object )"Jump to a group" ) );

    public object WatermarkContent
    {
      get
      {
        return ( object )this.GetValue( GroupNavigationSearchBox.WatermarkContentProperty );
      }
      set
      {
        this.SetValue( GroupNavigationSearchBox.WatermarkContentProperty, value );
      }
    }

    #endregion

    #region WatermarkContentTemplate Property

    public static readonly DependencyProperty WatermarkContentTemplateProperty = DependencyProperty.Register(
      "WatermarkContentTemplate",
      typeof( DataTemplate ),
      typeof( GroupNavigationSearchBox ),
      new PropertyMetadata( ( DataTemplate )null ) );

    public DataTemplate WatermarkContentTemplate
    {
      get
      {
        return ( DataTemplate )this.GetValue( GroupNavigationSearchBox.WatermarkContentTemplateProperty );
      }
      set
      {
        this.SetValue( GroupNavigationSearchBox.WatermarkContentTemplateProperty, value );
      }
    }

    #endregion

    #region Value Property

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
      "Value",
      typeof( object ),
      typeof( GroupNavigationSearchBox ),
      new PropertyMetadata(
        ( object )null,
        new PropertyChangedCallback( GroupNavigationSearchBox.OnValueChanged ) ) );

    public object Value
    {
      get
      {
        return ( object )this.GetValue( GroupNavigationSearchBox.ValueProperty );
      }
      set
      {
        this.SetValue( GroupNavigationSearchBox.ValueProperty, value );
      }
    }

    private static void OnValueChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
    }

    #endregion

    #region FindGroupCommand Property (Command)

    public static readonly DependencyProperty FindGroupCommandProperty = DependencyProperty.Register(
      "FindGroupCommand",
      typeof( ICommand ),
      typeof( GroupNavigationSearchBox ),
      new PropertyMetadata( null ) );

    public ICommand FindGroupCommand
    {
      get
      {
        return ( ICommand )this.GetValue( GroupNavigationSearchBox.FindGroupCommandProperty );
      }
      private set
      {
        this.SetValue( GroupNavigationSearchBox.FindGroupCommandProperty, value );
      }
    }

    #endregion

    public override void OnApplyTemplate()
    {
      base.OnApplyTemplate();

      m_searchTextBox = this.GetTemplateChild( "SearchTextBox" ) as TextBox;

      this.UpdateCommandsCanExecute();
    }

    protected override void OnKeyDown( KeyEventArgs e )
    {
      base.OnKeyDown( e );

      if( e.Handled )
        return;

      // Raise FindGroupCommand when Enter is pressed without Shift
      if( ( e.Key == Key.Enter ) && ( ( Keyboard.Modifiers & ModifierKeys.Shift ) != ModifierKeys.Shift ) )
      {
        if( this.FindGroupCommand.CanExecute( null ) )
        {
          this.FindGroupCommand.Execute( null );
        }

        e.Handled = true;
      }
    }

    protected override void OnLostFocus( RoutedEventArgs e )
    {
      base.OnLostFocus( e );

      // Reset the text so that the search bar goes back to original template
      this.ClearValue( GroupNavigationSearchBox.ValueProperty );
    }

    internal void AttachCommand()
    {
      if( this.FindGroupCommand == null )
      {
        this.FindGroupCommand = new DataGridCommand( new Action<object>( this.OnFindGroupExecute ), new Func<object, bool>( this.OnFindGroupCanExecute ) );
      }
    }

    internal void ReleaseCommand()
    {
      this.FindGroupCommand = null;
    }

    internal void UpdateCommandsCanExecute()
    {
      DataGridCommand findGroupCommand = this.FindGroupCommand as DataGridCommand;
      if( findGroupCommand != null )
      {
        findGroupCommand.RaiseCanExecuteChanged();
      }
    }

    internal bool SetFocusOnSearchTextBox()
    {
      if( m_searchTextBox == null )
        return false;

      return m_searchTextBox.Focus();
    }

    private bool OnFindGroupCanExecute( object parameter )
    {
      return ( m_searchTextBox != null );
    }

    private void OnFindGroupExecute( object parameter )
    {
      this.DoSearch();
      this.UpdateCommandsCanExecute();

      // Reset the text so that the search bar goes back to original template
      this.ClearValue( GroupNavigationSearchBox.ValueProperty );
    }

    private string GetTrimmedString( string searchString )
    {
      //Set the trimming character to white space
      string delimiter = " ";
      if( !string.IsNullOrEmpty( searchString ) )
        return searchString.Trim( delimiter.ToCharArray() );

      return searchString;
    }

    private void DoSearch()
    {
      //Get the group string that will be searched for.
      string targetValue = this.GetTrimmedString( ( string )this.Value );
      if( string.IsNullOrEmpty( targetValue ) )
        return;

      this.EventManager.RaiseEvent( GroupNavigationSearchBox.OnSearchGroupEvent, new XceedRoutedEventSearchGroupEventArgs( this, targetValue ) );
    }

    #region Private Fields

    private TextBox m_searchTextBox;

    #endregion
  }
}
